package net.qiqbframework.loadhanding;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.Registration;
import net.qiqbframework.lifecycle.LifecycleHandlerRegister;
import net.qiqbframework.lifecycle.Phase;
import net.qiqbframework.messaging.*;
import net.qiqbframework.messaging.task.DefaultMessageTask;
import net.qiqbframework.messaging.task.MessageTask;
import net.qiqbframework.modelling.domain.AggregateModel;
import net.qiqbframework.modelling.domain.AggregateModelFactory;
import net.qiqbframework.modelling.domain.AggregateModellingException;
import net.qiqbframework.modelling.domain.BizIdentifierModel;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

import static net.qiqbframework.commandhandling.GenericCommandResultMessage.asCommandResultMessage;
import static net.qiqbframework.common.BuilderUtils.assertNonNull;

@Slf4j
public class DefaultAggregateLoadBus implements AggregateLoadBus {
    /**
     * key ： aggregateNaming
     */
    private final ConcurrentMap<String, MessageHandler<? super LoadMessage<?, ?>>> subscriptions = new ConcurrentHashMap<>();
    private final List<MessageHandlerInterceptor<? super LoadMessage<?,?>>> handlerInterceptors = new CopyOnWriteArrayList<>();

    private final AggregateModelFactory aggregateModelFactory;

    protected DefaultAggregateLoadBus(AggregateLoadBusImplBuilder builder) {
        builder.validate();
        this.aggregateModelFactory = builder.aggregateModelFactory;

    }



    @Override
    public <A> A load(@Nonnull LoadMessage<?, A> loadMessage) {

        Optional<MessageHandler<? super LoadMessage<?, ?>>> optionalHandler = findLoadHandler(loadMessage.getAggregateNaming());

        if (optionalHandler.isPresent()) {

            MessageTask<LoadMessage<?,A>> messageMessageTask = DefaultMessageTask.startAndGet(loadMessage);

            InterceptorChain chain = new DefaultInterceptorChain<>(messageMessageTask, handlerInterceptors, optionalHandler.get());
            try {
                final ResultMessage<Object> loadResult = messageMessageTask.executeWithResult(chain::proceed, throwable -> false);
                return  (A) loadResult.getPayload();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }
        return null;
    }


    @Override
    public Registration subscribe(@Nonnull String aggregateNaming, @Nonnull MessageHandler<? super LoadMessage<?, ?>> handler) {
        assertNonNull(handler, "handler may not be null");
        subscriptions.compute(aggregateNaming, (k, existingHandler) -> {
            if (existingHandler == null || existingHandler == handler) {
                return handler;
            } else {
                throw new CreateLoadException("存在多个加载器");
            }
        });
        return () -> subscriptions.remove(aggregateNaming, handler);
    }



    public Optional<MessageHandler<? super LoadMessage<?, ?>>> findLoadHandler(@Nonnull String businessIdName) {
        return Optional.ofNullable(subscriptions.get(businessIdName));
    }


    public static AggregateLoadBusImplBuilder builder() {
        return new AggregateLoadBusImplBuilder();
    }

    @Override
    public void registerLifecycleHandler(@Nonnull LifecycleHandlerRegister register) {

        register.onStart(
                Phase.LOCAL_MESSAGE_HANDLER_VERIFY,
                () -> {
                    // 验证每个聚合对象的biz对应一个加载器
                    for (String aggregateNaming : aggregateModelFactory.getAllAggregateNaming()) {
                        final Optional<AggregateModel<Object>> aggregateModel = aggregateModelFactory.getModel(aggregateNaming);
                        if (aggregateModel.isEmpty()) {
                            // 理论上不会出现这种情况
                            throw new AggregateModellingException("未初始化");
                        }

                        final Optional<MessageHandler<? super LoadMessage<?, ?>>> loadHandler = findLoadHandler(aggregateNaming);
                        if (loadHandler.isEmpty()) {
                            log.error("聚合 {} 未发现业务ID加载，将不能执行修改命令", aggregateNaming);
                        } else {
                            final MessageHandler<? super LoadMessage<?, ?>> aggregateLoadMessageHandler = loadHandler.get();
                            for (BizIdentifierModel<?> businessIdModel : aggregateModel.get().allBizIdentifierModels()) {


                            }
                        }
                    }
                }
        );
    }
}
